package com.ccp.dev.workflow.service.bpm.cmd;

import com.ccp.dev.core.util.AppUtil;
import com.ccp.dev.core.util.BeanUtils;
import com.ccp.dev.core.util.StringUtil;
import com.ccp.dev.workflow.model.BpmNodeSet;
import com.ccp.dev.workflow.model.FlowNodeInfo;
import com.ccp.dev.workflow.model.NodeCache;
import com.ccp.dev.workflow.service.BpmNodeSetService;
import org.flowable.common.engine.impl.interceptor.Command;
import org.flowable.common.engine.impl.interceptor.CommandContext;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.impl.RuntimeServiceImpl;
import org.flowable.engine.impl.persistence.entity.ExecutionEntity;
import org.flowable.engine.TaskService;
import org.flowable.engine.impl.TaskServiceImpl;
import org.flowable.task.service.impl.persistence.entity.TaskEntity;

import java.util.List;
import java.util.Map;

/**
 * ClassDescribe:
 * 流程任务是否允许驳回。
 * <pre>
 * 1.当前节点为分发节点不允许驳回。
 * 2.当前节点为汇总节点不允许驳回。
 * 3.如果当前节点为流程定义的第一个节点并且不是外部子流程实例不允许驳回。
 * 4.前面节点不是userTask或者exclusiveGateway不允许驳回。
 * 5.前面节点是userTask，但是是分发任务，不允许驳回
 * </pre>
 * @author :jiayueqiao
 * Date: 2019-10-28
 * Since:1
 */
public class TaskAllowRejectCmd implements Command<Boolean> {

    private String taskId;

    public TaskAllowRejectCmd(String taskId){
        this.taskId=taskId;
    }

    private ExecutionEntity getSuperExecutionEnt(ExecutionEntity executionEntity){
        return executionEntity.getSuperExecution();
    }

    @Override
    public Boolean execute(CommandContext commandContext) {
        BpmNodeSetService bpmNodeSetService=AppUtil.getBean(BpmNodeSetService.class);
        TaskService taskService=(TaskServiceImpl)AppUtil.getBean("taskServiceBean");
        RuntimeService runtimeService=(RuntimeServiceImpl)AppUtil.getBean("runtimeServiceBean");
        TaskEntity taskEnt= (TaskEntity)taskService.createTaskQuery().taskId(taskId).singleResult();

        String executionId = taskEnt.getProcessInstanceId();
        ExecutionEntity executionEntity= (ExecutionEntity)runtimeService.createExecutionQuery().executionId(executionId).singleResult();
        if(executionEntity==null){
            return false;
        }
        String procDefId=taskEnt.getProcessDefinitionId();
        String nodeId=taskEnt.getTaskDefinitionKey();

        BpmNodeSet bpmNodeSet;

        //获取当前节点的配置，判断是否是分发节点，是则不能有驳回功能
        bpmNodeSet = bpmNodeSetService.getByProcDefIdNodeIdOrParentProcDefId(nodeId,procDefId,null);
        if (BeanUtils.isNotEmpty(bpmNodeSet)) {
            if (BeanUtils.isNotEmpty(bpmNodeSet.getNodeType()) && bpmNodeSet.getNodeType()==1) {
                return false;
            }
        }

        //节点为汇总节点
        bpmNodeSet =bpmNodeSetService.getByProcDefIdJoinTaskKey(procDefId, nodeId);
        if(BeanUtils.isNotEmpty(bpmNodeSet)){
            return false;
        }

        boolean rtn=NodeCache.isFirstNode(procDefId, nodeId);
        //当前节点为流程第一个节点，并且流程实例非子流程实例。
        if(rtn ){
            if(StringUtil.isEmpty(executionEntity.getSuperExecutionId()) ){
                return false;
            }
            else{
                ExecutionEntity superEnt=getSuperExecutionEnt(executionEntity);
                nodeId=superEnt.getActivityId();
                procDefId=superEnt.getProcessDefinitionId();
            }
        }

        Map<String, FlowNodeInfo> map = NodeCache.getByProcDefId(procDefId);
        FlowNodeInfo flowNode = map.get(nodeId);
        List<FlowNodeInfo> preFlowNodeList = flowNode.getPreFlowNodesInfo();
        for (FlowNodeInfo preNode : preFlowNodeList) {
            if(!FlowNodeInfo.TYPE_USERTASK.equals(preNode.getNodeType()) && !FlowNodeInfo.TYPE_EXCLUSIVEGATEWAY.equals(preNode.getNodeType())){
                return false;
            }
            //2019-11-15 jyq新增 前面是分发任务，不允许驳回
            bpmNodeSet = bpmNodeSetService.getByProcDefIdNodeIdOrParentProcDefId(preNode.getNodeId(),procDefId,null);
            if (BeanUtils.isNotEmpty(bpmNodeSet)) {
                if (BeanUtils.isNotEmpty(bpmNodeSet.getNodeType()) && bpmNodeSet.getNodeType()==1) {
                    return false;
                }
            }
        }

        return true;
    }
}
